package git.soulbgm.stats;

import git.soulbgm.thread.ThreadPoolManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 流量统计类
 *
 * <p>收集和统计代理服务器的流量数据，包括请求数、数据包大小、
 * 响应时间等指标。提供实时统计和历史数据查询功能。</p>
 *
 * <p>统计指标：</p>
 * <ul>
 *   <li>总请求数</li>
 *   <li>数据传输量</li>
 *   <li>响应时间分布</li>
 *   <li>错误率统计</li>
 *   <li>后端服务器负载分布</li>
 * </ul>
 *
 * @author soulbgm
 * @version 1.0
 * @since 1.0
 */
public class TrafficStats {
    private static final Logger logger = LoggerFactory.getLogger(TrafficStats.class);

    /**
     * 总接收数据包数
     */
    private final AtomicLong totalReceivedPackets = new AtomicLong(0);
    /**
     * 总接收字节数
     */
    private final AtomicLong totalReceivedBytes = new AtomicLong(0);
    /**
     * 总转发数据包数
     */
    private final AtomicLong totalForwardedPackets = new AtomicLong(0);
    /**
     * 总转发字节数
     */
    private final AtomicLong totalForwardedBytes = new AtomicLong(0);

    /**
     * 周期接收数据包数
     */
    private final AtomicLong periodReceivedPackets = new AtomicLong(0);
    /**
     * 周期接收字节数
     */
    private final AtomicLong periodReceivedBytes = new AtomicLong(0);
    /**
     * 周期转发数据包数
     */
    private final AtomicLong periodForwardedPackets = new AtomicLong(0);
    /**
     * 周期转发字节数
     */
    private final AtomicLong periodForwardedBytes = new AtomicLong(0);

    /**
     * 线程池管理器
     */
    private final ThreadPoolManager threadPoolManager;
    /**
     * 统计任务Future
     */
    private ScheduledFuture<?> statsFuture;
    /**
     * 服务启动时间
     */
    private final long startTime;

    /**
     * 1KB的字节数
     */
    private static final long KB = 1024L;
    /**
     * 1MB的字节数
     */
    private static final long MB = KB * 1024L;

    /**
     * 创建流量统计实例
     *
     * @param threadPoolManager 线程池管理器
     */
    public TrafficStats(ThreadPoolManager threadPoolManager) {
        this.threadPoolManager = threadPoolManager;
        this.startTime = System.currentTimeMillis();
    }

    /**
     * 启动流量统计
     */
    public void start() {
        statsFuture = threadPoolManager.getScheduleExecutor().scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                printStats();
                resetPeriodStats();
            }
        }, 1, 1, TimeUnit.MINUTES);
    }

    /**
     * 停止流量统计
     */
    public void stop() {
        if (statsFuture != null) {
            statsFuture.cancel(false);
        }
    }

    /**
     * 记录接收到的数据包
     *
     * @param bytes 数据包大小（字节）
     */
    public void recordReceived(int bytes) {
        totalReceivedPackets.incrementAndGet();
        totalReceivedBytes.addAndGet(bytes);
        periodReceivedPackets.incrementAndGet();
        periodReceivedBytes.addAndGet(bytes);
    }

    /**
     * 记录转发的数据包
     *
     * @param bytes 数据包大小（字节）
     */
    public void recordForwarded(int bytes) {
        totalForwardedPackets.incrementAndGet();
        totalForwardedBytes.addAndGet(bytes);
        periodForwardedPackets.incrementAndGet();
        periodForwardedBytes.addAndGet(bytes);
    }

    /**
     * 重置周期统计数据
     */
    private void resetPeriodStats() {
        periodReceivedPackets.set(0);
        periodReceivedBytes.set(0);
        periodForwardedPackets.set(0);
        periodForwardedBytes.set(0);
    }

    /**
     * 获取运行时间
     *
     * @return 格式化的运行时间字符串
     */
    private String getRunningTime() {
        long now = System.currentTimeMillis();
        long runningTime = now - startTime;
        long days = TimeUnit.MILLISECONDS.toDays(runningTime);
        long hours = TimeUnit.MILLISECONDS.toHours(runningTime) % 24;
        long minutes = TimeUnit.MILLISECONDS.toMinutes(runningTime) % 60;

        if (days > 0) {
            return String.format("%d天%d小时%d分钟", days, hours, minutes);
        } else if (hours > 0) {
            return String.format("%d小时%d分钟", hours, minutes);
        } else {
            return String.format("%d分钟", minutes);
        }
    }

    /**
     * 根据字节数获取合适的显示格式
     *
     * @param bytes 字节数
     * @return 格式化后的字符串，包含大小和单位
     */
    private String formatBytes(long bytes) {
        if (bytes < KB) {
            return String.format("%d字节", bytes);
        } else if (bytes < MB) {
            return String.format("%.2fKB", bytes / (double) KB);
        } else {
            return String.format("%.2fMB", bytes / (double) MB);
        }
    }

    /**
     * 计算速率（每秒）
     *
     * @param bytes 字节数
     * @return 格式化后的速率字符串
     */
    private String formatSpeed(long bytes) {
        double bytesPerSecond = bytes / 60.0; // 一分钟内的平均速率
        if (bytesPerSecond < KB) {
            return String.format("%.2f字节/秒", bytesPerSecond);
        } else if (bytesPerSecond < MB) {
            return String.format("%.2fKB/秒", bytesPerSecond / KB);
        } else {
            return String.format("%.2fMB/秒", bytesPerSecond / MB);
        }
    }

    /**
     * 输出统计信息
     */
    private void printStats() {
        // 获取周期统计数据
        long prp = periodReceivedPackets.get();
        long prb = periodReceivedBytes.get();
        long pfp = periodForwardedPackets.get();
        long pfb = periodForwardedBytes.get();

        // 获取总量统计数据
        long trp = totalReceivedPackets.get();
        long trb = totalReceivedBytes.get();
        long tfp = totalForwardedPackets.get();
        long tfb = totalForwardedBytes.get();

        // 输出统计信息
        logger.info("\n流量统计报告 (运行时间: {})\n" +
                        "周期统计(1分钟):\n" +
                        "  接收: {} 个数据包 ({}, {})\n" +
                        "  转发: {} 个数据包 ({}, {})\n" +
                        "总量统计:\n" +
                        "  接收: {} 个数据包 ({})\n" +
                        "  转发: {} 个数据包 ({})",
                getRunningTime(),
                prp, formatBytes(prb), formatSpeed(prb),
                pfp, formatBytes(pfb), formatSpeed(pfb),
                trp, formatBytes(trb),
                tfp, formatBytes(tfb)
        );
    }
}